(function(window, document) {
    function mScroll(el, options) {
        // 配置
        this.options = {
            scrollX: options.scrollX || false,// 允许横向滚动？默认不允许
            scrollY: options.scrollY || true,// 允许纵向滚动？默认允许
            startX: options.startX || 0,// x轴开始位置
            startY: options.startY || 0,// y轴开始位置
            speed: options.speed || 27,// 滚动速度，数值越大速度越快
            maxTouchMoveSpeed: options.maxTouchMoveSpeed || 2000,// 最大触摸移动速度限制，一般不设置封顶，正常操作1000内
            scrollTime: options.scrollTime || 2000, // 惯性滚动时长 默认2000ms
            bounceTime: options.bounceTime || 600,// 回弹时间
            overflowDrag: options.overflowDrag || 0.32,// 溢出阻力，越小阻力越大
        }
        // 对象准备
        this.wrapper = typeof(el) == 'string' ? document.querySelector(el) : el;// 获取包裹对象
        this.wrapper.style.overflow = "hidden";
        this.wrapper.innerHTML = "<div>" + this.wrapper.innerHTML + "</div>"; // 重封装内容，包裹滚动
        this.scroller = this.wrapper.children[0];// 获取内容对象

        this.startCoor = {};// 开始的坐标
        this.nowCoor = {};// 当前的坐标
        this.endCoor = {};// 结束的坐标
        this.finishPosition = {};// 惯性滚动的最后位置
        this.touchMoveSpeed = {};// 获取触摸移动速度
        this.pageDeviation = {};// 页面当前偏移量
        this.deviation = {};// 触摸滚动式偏移量
        this.inScrolling = false; // 是否在滚动中
        this.inTouchMoveing = false; // 是否在触摸滚动中

        this.timeoutScrolling;// 滚动状态修改的延时

        this._init();// 初始化

        // 绑定监听事件
        this.wrapper.addEventListener('touchstart', this.touchStart.bind(this));
        this.wrapper.addEventListener('touchmove', this.pageMoving.bind(this));
        this.wrapper.addEventListener('touchend', this.touchEnd.bind(this));
    }
    mScroll.prototype = {
        version: "1.0.0",
        _init: function() {// 初始化变量
            this.wrapperHeight = this.wrapper.offsetHeight;// 包裹高度
            this.wrapperWidth = this.wrapper.offsetWidth;// 包裹宽度
            this.scrollerHeight = this.scroller.offsetHeight;// 内容高度
            this.scrollerWidth = this.scroller.offsetWidth;// 内容宽度
            this.maxScrollX = this.wrapperWidth - this.scrollerWidth;// x轴可滚动最大值
            this.maxScrollY = this.wrapperHeight - this.scrollerHeight;// y轴可滚动最大值
            this.scrollTo(this.options.startX < this.maxScrollX ? this.maxScrollX : this.options.startX, this.options.startY < this.maxScrollY ? this.maxScrollY : this.options.startY, 0);// 跳到滚动条初始位置，但最大不超过可滚动范围
        },
        refresh: function() {// 刷新mScroll
            this.wrapperHeight = this.wrapper.offsetHeight;// 包裹高度
            this.wrapperWidth = this.wrapper.offsetWidth;// 包裹宽度
            this.scrollerHeight = this.scroller.offsetHeight;// 内容高度
            this.scrollerWidth = this.scroller.offsetWidth;// 内容宽度

            this.maxScrollX = this.wrapperWidth - this.scrollerWidth;// x轴可滚动最大值
            this.maxScrollY = this.wrapperHeight - this.scrollerHeight;// y轴可滚动最大值
        },
        imgMonitor: function() {// 图片加载完成监听重新刷新mScroll
            var _this = this;
            var imgDOMS = this.scroller.querySelectorAll('img');
            var imgLoadTimeout;
            for(let i in imgDOMS) {
                if(typeof(imgDOMS[i]) == "object") {// 避免空DOM报错
                    imgDOMS[i].onload = function() {
                        // 0.5s内的更新统一刷新scrollView
                        clearTimeout(imgLoadTimeout);
                        imgLoadTimeout = setTimeout(function() {
                            _this.refresh();
                        }, 500);
                    };
                }
            }
        },
        xBounceCalc: function(targetPosition) {// 溢出回弹阻力计算 param=(目标位置， 父元素size， 子元素size， 阻力大小)
            var overflowDrag = this.options.overflowDrag;
            if(targetPosition > 0) {// y轴顶部溢出
                return (targetPosition * overflowDrag);
            }else if(targetPosition < this.maxScrollX) {// y轴底部溢出
                return (this.maxScrollX + ((targetPosition - this.wrapperWidth + this.scrollerWidth) * overflowDrag));
            }else {
                return targetPosition;
            }
        },
        yBounceCalc: function(targetPosition) {// 纵向
            var overflowDrag = this.options.overflowDrag;
            if(targetPosition > 0) {// y轴顶部溢出
                return (targetPosition * overflowDrag);
            }else if(targetPosition < this.maxScrollY) {// y轴底部溢出
                return (this.maxScrollY + ((targetPosition - this.wrapperHeight + this.scrollerHeight) * overflowDrag));
            }else {
                return targetPosition;
            }
        },
        scrollTo: function(x, y, animationTime) {// 页面滚动接口
            if(animationTime != 0) {// 有执行动画时间
                var timeFunction = "cubic-bezier(0, .1, .35, 1)";
                if(x > 0 || x < this.maxScrollX || y > 0 || y < this.maxScrollY) {// 边界溢出回弹动画曲线设置
                    timeFunction = "cubic-bezier(0, .1, .15, 1.5)";
                    animationTime = animationTime * 0.3;
                }
                // 阻止边界溢出
                if(x >= 0) {
                    x = 0;
                }else if(x < this.maxScrollX) {
                    x = this.maxScrollX;
                }
                if(y >= 0) {
                    y = 0;
                }else if(y < this.maxScrollY) {
                    y = this.maxScrollY;
                }
                this.scroller.style.transform = "translate3d(" + x +"px, " + y + "px, 0)";// 设置样式
                this.scroller.style.transitionTimingFunction = timeFunction;// 设置滚动动画曲线
                this.scroller.style.transitionDuration = animationTime + "ms";// 设置滚动时间
            }else {
                // 边界溢出阻力
                x = this.xBounceCalc(x);
                y = this.yBounceCalc(y);
                this.scroller.style.transform = "translate3d(" + x +"px, " + y + "px, 0)";// 设置样式
                this.scroller.style.transitionDuration = animationTime + "ms";// 设置滚动时间
            }
        },
        touchStart: function(e) {
            var _this = this;
            if(this.inScrolling) {// 滚动状态中
                e.preventDefault();
                e.stopPropagation();
            }
            var transform = window.getComputedStyle(_this.scroller).getPropertyValue("transform").match(/\d+|\-\d+\.?\d+/g) || [];// 获取当前页面偏移量信息
            this.pageDeviation.x = parseInt(transform[4]) || 0;// 页面当前偏移量x
            this.pageDeviation.y = parseInt(transform[5]) || 0; // 页面当前偏移量y
            // finishPosition = pageDeviation;// 重新初始化结束为止，避免继续滚动
            this.scrollTo(this.pageDeviation.x, this.pageDeviation.y, 0);
            // 存储开始坐标
            this.startCoor.x = e.changedTouches[0].pageX;
            this.startCoor.y = e.changedTouches[0].pageY;
        },
        pageMoving: function(e) {
            e.preventDefault();
            var moveCritical = 10;// 移动临界值，超过此值则阻止事件冒泡
            if((this.options.scrollX && Math.abs(this.nowCoor.x - this.startCoor.x) > moveCritical) || (this.options.scrollY && Math.abs(this.nowCoor.y - this.startCoor.y) > moveCritical)) {
                this.inTouchMoveing = true;
            }
            // 计算移动速度
            this.touchMoveSpeed.x = parseInt(e.changedTouches[0].pageX - this.nowCoor.x) || 0;
            this.touchMoveSpeed.y = parseInt(e.changedTouches[0].pageY - this.nowCoor.y) || 0;
            // 限制移动速度最大值
            this.touchMoveSpeed.x = Math.abs(this.touchMoveSpeed.x) > this.maxTouchMoveSpeed ? (this.touchMoveSpeed.x > 0 ? this.maxTouchMoveSpeed : -this.maxTouchMoveSpeed) : this.touchMoveSpeed.x;
            this.touchMoveSpeed.y = Math.abs(this.touchMoveSpeed.y) > this.maxTouchMoveSpeed ? (this.touchMoveSpeed.y > 0 ? this.maxTouchMoveSpeed : -this.maxTouchMoveSpeed) : this.touchMoveSpeed.y;
            // 存储当前坐标
            this.nowCoor.x = e.changedTouches[0].pageX;
            this.nowCoor.y = e.changedTouches[0].pageY;
            // 计算即时偏移量
            this.deviation.x = this.options.scrollX ? (this.nowCoor.x - this.startCoor.x + this.pageDeviation.x) : 0;
            this.deviation.y = this.options.scrollY ? (this.nowCoor.y - this.startCoor.y + this.pageDeviation.y) : 0;
            this.scrollTo(this.deviation.x, this.deviation.y, 0);
        },
        touchEnd: function(e) {
            var _this = this;
            var moveCritical = 10;// 移动临界值，超过此值则阻止事件冒泡
            if((this.options.scrollX && Math.abs(this.nowCoor.x - this.startCoor.x) > moveCritical) || (this.options.scrollY && Math.abs(this.nowCoor.y - this.startCoor.y) > moveCritical)) {
                e.preventDefault();
            }

            var moveSpeedCritical = 10;// 移动速度临界值，超过此值则阻止事件冒泡
            if((this.options.scrollY && Math.abs(this.touchMoveSpeed.y) > moveSpeedCritical) || (this.options.scrollX && Math.abs(this.touchMoveSpeed.x) > moveSpeedCritical)) {// 惯性滚动
                e.preventDefault();
                this.inScrolling = true;
                this.finishPosition.x = this.options.scrollX ? ((this.touchMoveSpeed.x * this.options.speed) + this.deviation.x) : 0;
                this.finishPosition.y = this.options.scrollY ? ((this.touchMoveSpeed.y * this.options.speed) + this.deviation.y) : 0;
                this.scrollTo(this.finishPosition.x, this.finishPosition.y, this.options.scrollTime);
                clearTimeout(_this.timeoutScrolling);// 清除滚动状态修改的延时
                this.timeoutScrolling = setTimeout(function() {
                    _this.inScrolling = false;
                }, this.options.scrollTime);
            }else if(this.deviation.x > 0 || this.deviation.x < this.maxScrollX || this.deviation.y > 0 || this.deviation.y < this.maxScrollY) {// 触摸溢出边界
                // 返回边界
                if(this.deviation.x > 0) {
                    this.deviation.x = 0;
                }else if(this.deviation.x < this.maxScrollX) {
                    this.deviation.x = this.maxScrollX;
                }
                if(this.deviation.y > 0) {
                    this.deviation.y = 0;
                }else if(this.deviation.y < this.maxScrollY) {
                    this.deviation.y = this.maxScrollY;
                }
                this.scrollTo(this.deviation.x, this.deviation.y, this.options.bounceTime * 0.5);// 设置回弹返回边界
            }else if(this.inScrolling || this.inTouchMoveing) {// 滚动中，阻止默认事件
                e.preventDefault();
                clearTimeout(_this.timeoutScrolling);// 清除滚动状态修改的延时
                // 清除滚动中状态
                _this.inScrolling = false;
                _this.inTouchMoveing = false;
            }
        }
    }


    if ( typeof module != 'undefined' && module.exports ) {
    	module.exports = mScroll;
    } else if ( typeof define == 'function' && define.amd ) {
        define( function () { return mScroll; } );
    } else {
    	window.mScroll = mScroll;
    }
})(window, document);
